/*
 * tracks frequency and trending of phrases
 */
package trend

import (
	"container/ring"
	"time"
	"bufio"
	"io"
	"bytes"
)


const N = 20
const M = 5

type Occurence struct {
	Key int
	Count int
	Rate float64
	Time time.Time
}

type Summary map[string]float64

type History []Occurence

type RankOrder struct {
	Order []string
	Pos map[string]int
}

type Dictionary struct {
	Keys map[string]int
	Words []string
}

type Model struct {
	Series map[string]*ring.Ring
	Rank *RankOrder
	Dictionary *Dictionary
	Ignore *Dictionary
}

func NewRankOrder() *RankOrder {
	return &RankOrder{make([]string, 0), make(map[string]int)}
}

func NewDictionary() *Dictionary {
	return &Dictionary{make(map[string]int), make([]string, 0)}
}


func NewModel() *Model {

	return &Model{make(map[string]*ring.Ring), NewRankOrder(), NewDictionary(), NewDictionary()}
}

func (d *Dictionary) Key(text string) int {

	_, ok := d.Keys[text]

	if !ok {
		d.Add(text)
	}

	return d.Keys[text]
}

func (d *Dictionary) Add(text string) {

	if d.Contains(text) {
		return
	}

	d.Keys[text] = len(d.Words)
	d.Words = append(d.Words, text)
}

func (d *Dictionary) Load(in io.Reader) {

	reader := bufio.NewReader(in)

	for line, _, err := reader.ReadLine(); err == nil; line, _, err = reader.ReadLine() {
		d.Add(bytes.NewBuffer(line).String())
	}
}

func (d *Dictionary) Contains(text string) bool {

	_, ok := d.Keys[text]

	return ok
}

func (m *Model) Add(text string) {
	m.add(text, time.Now())
}

func (m *Model) add(text string, now time.Time) {

	if m.Ignore.Contains(text) {
		return
	}

	count := 0
	rate := 0.0
	series, ok := m.Series[text]

	if !ok {
		// first occurence of this word
		m.Series[text] = ring.New(N)
	} else {
		// this occurence based on previous occurence
		head := m.Series[text].Value.(Occurence)
		count = tail.Count + 1
		rate = float64(count - head.Count) / now.Sub(head.Time).Seconds()
	}

	occurence := &Occurence{Key:m.Dictionary.Key(text), Count:count, Rate:rate, Time:now}
	m.Head[text].Next()
	m.Head[text].Value = occurence

	if m.Head[text].Len() 
}

func (m *Model) Since(text string, since int64, res chan Occurence) {

	ch := make(chan feed.Entry)

	m.Series[text].Since(since, ch)

	for e := range ch {
		res <- e.Data.(Occurence)
	}

	return
}

func (r *RankOrder) Add(text string) {

	bubble := func () {

		pos := r.Pos[text]
		
		if pos > 0 {
			aboveword := r.Order[pos - 1]
			r.Pos[aboveword] = pos
			r.Order[pos] = aboveword
			r.Pos[text] = pos - 1
			r.Order[pos - 1] = text
		}
	}

	_, ok := r.Pos[text]
	if !ok {
		// add if not there already
		bottom := len(r.Order)
		r.Order = append(r.Order, text)
		r.Pos[text] = bottom
	}

	// reinforce word
	for i := 0; i < 30; i++ {
		bubble()
	} 
}

func (r *RankOrder) Top(n int) []string {

	if n > len(r.Order) {
		n = len(r.Order)
	}

	return r.Order[0:n]
}
